package cn.zyx.user.service.impl;

import cn.zyx.basic.exception.BusinessException;
import cn.zyx.basic.service.impl.BaseServiceImpl;
import cn.zyx.basic.util.MD5Utils;
import cn.zyx.basic.util.StrUtils;
import cn.zyx.user.constant.UserConstant;
import cn.zyx.user.domain.LoginInfo;
import cn.zyx.user.domain.User;
import cn.zyx.user.dto.UserDto;
import cn.zyx.user.mapper.LoginInfoMapper;
import cn.zyx.user.mapper.UserMapper;
import cn.zyx.user.service.IUserService;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;
import sun.security.provider.MD5;

@Service
@Transactional(readOnly = true,propagation = Propagation.SUPPORTS)  // 加上事务
public class UserServiceImpl extends BaseServiceImpl<User> implements IUserService {

    @Autowired
    private UserMapper userMapper;

    @Autowired
    private LoginInfoMapper loginInfoMapper;

    @Autowired
    private RedisTemplate redisTemplate;

    @Override
    public User loadByPhone(String phone) {
        return userMapper.loadByPhone(phone);
    }

    @Override
    @Transactional
    public void registerCode(UserDto userDto) {
        // 校验 -- 空校验 -- 每个信息都要判断
        if (StringUtils.isEmpty(userDto.getPhone()) ||
                StringUtils.isEmpty(userDto.getVerifyCode()) ||
                StringUtils.isEmpty(userDto.getPassword()) ||
                StringUtils.isEmpty(userDto.getConfirmPwd()) ){
            throw new BusinessException("请输入完整信息!");
        }
        // 校验 -- 两次密码是否一致
        if (!userDto.getPassword().equals(userDto.getConfirmPwd())){
            throw new BusinessException("两次输入的密码请保持一致!");
        }
        // 校验 -- 是否被注册
        LoginInfo obj = loginInfoMapper.loadByDto(userDto);
        if (obj != null){
            throw new BusinessException("用户已经存在!");
        }
        // 验证码是否存在
        Object codeObj = redisTemplate.opsForValue().get(UserConstant.USER_VERFIY_CODE+":"+userDto.getPhone());
        // 验证码是否已经过期
        if (codeObj == null){
            throw new BusinessException("验证码已过期,请重新发送!");
        }
        String code = ((String)codeObj).split(":")[0];
        // 验证码是否正确
        if (!userDto.getVerifyCode().equalsIgnoreCase(code)){
            throw new BusinessException("验证码错误！");
        }
        // 登录成功 -- 登录信息表保存
        // 将dto转换成实体对象
        User user = userDto2User(userDto);
        LoginInfo loginInfo = user2LoginInfo(user);
        loginInfoMapper.save(loginInfo);            // 返回登录信息的自增id，用户表需要
        // 登录成功 -- 用户表保存
        user.setInfo(loginInfo);//引用属性传值
        userMapper.save(user);
    }

    /**
     * 将dto转换成实体对象
     * @param userDto
     * @return
     */
    private User userDto2User(UserDto userDto) {
        // 定义需要返回的对象
        User user = new User();
        // 封装数据
        user.setUsername(userDto.getPhone());
        user.setPhone(userDto.getPhone());
        // 通过工具类生成盐值
        String salt = StrUtils.getComplexRandomString(32);
        // 通过工具类获取加密和加盐的密码
        String md5Pwd = MD5Utils.encrypByMd5(userDto.getPassword()+salt);
        user.setSalt(salt);
        user.setPassword(md5Pwd);
        // 返回
        return user;
    }

    private LoginInfo user2LoginInfo(User user) {
        // 定义需要返回的对象
        LoginInfo info = new LoginInfo();
        // 封装数据 -- 这里直接使用工具类拷贝，同名原则拷贝属性值 -- 这个工具类也是spring提供的
        BeanUtils.copyProperties(user, info);
        // 设置前端用户默认值
        info.setType(1);
        // 返回
        return info;
    }
}
